package base.java8;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.TimeInterval;

import java.io.IOException;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.function.*;

/**
 * *****************************************************************************************************************************************
 * 1. 任务创建
 * <p>
 * * {@link CompletableFuture#supplyAsync(Supplier)}           创建一个有返回值CompletableFuture
 * * {@link CompletableFuture#supplyAsync(Supplier, Executor)} 创建一个有返回值CompletableFuture,可自定义线程池
 * * {@link CompletableFuture#runAsync(Runnable)}              创建一个无返回值CompletableFuture
 * * {@link CompletableFuture#runAsync(Runnable, Executor)}    创建一个无返回值CompletableFuture,可自定义线程池
 * * {@link CompletableFuture#completedFuture(Object)}         是一个静态辅助方法，用来返回一个已经计算好的CompletableFuture
 * *****************************************************************************************************************************************
 * 2. 同步方法
 * <p>
 * * {@link CompletableFuture#isDone()}                          判断任务是否完成
 * * {@link CompletableFuture#cancel(boolean)}                   取消
 * * {@link CompletableFuture#isCancelled()}                     判断任务是否取消
 * * {@link CompletableFuture#get()}                             获取CompletableFuture异步之后的返回值,会抛出检查异常
 * * {@link CompletableFuture#get(long, TimeUnit)}               等待一段时间后,获取CompletableFuture异步之后的返回值
 * * {@link CompletableFuture#getNow(Object)}                    立即获取结果,如果没有结果就返回一个默认值
 * * {@link CompletableFuture#join()}                            获取CompletableFuture异步之后的返回值,不会抛出检查异常
 * * {@link CompletableFuture#complete(Object)}                  如果没完成设置一个默认值
 * * {@link CompletableFuture#completeExceptionally(Throwable)}  如果没完成就抛出异常
 * *****************************************************************************************************************************************
 * 3. 异步方法
 * <p>
 * * whenComplete：当任务完成时，对结果做一次消费（会捕获任务中的异常）
 * * {@link CompletableFuture#whenComplete(BiConsumer)}
 * * {@link CompletableFuture#whenCompleteAsync(BiConsumer)}
 * * {@link CompletableFuture#whenCompleteAsync(BiConsumer, Executor)}
 * <p>
 * * thenAccept：当任务完成时，对结果做一次消费（不会捕获任务中的异常）
 * * {@link CompletableFuture#thenAccept(Consumer)}
 * * {@link CompletableFuture#thenAcceptAsync(Consumer)}
 * * {@link CompletableFuture#thenAcceptAsync(Consumer, Executor)}
 * <p>
 * * handle：当任务完成时，对结果做一次转换（会捕获任务中的异常）
 * * {@link CompletableFuture#handle(BiFunction)}
 * * {@link CompletableFuture#handleAsync(BiFunction)}
 * * {@link CompletableFuture#handleAsync(BiFunction, Executor)}
 * <p>
 * * thenApply：当任务完成时，对结果做一次转换（不会捕获任务中的异常）
 * * {@link CompletableFuture#thenApply(Function)}
 * * {@link CompletableFuture#thenApplyAsync(Function)}
 * * {@link CompletableFuture#thenApplyAsync(Function, Executor)}
 * <p>
 * * thenRun：当任务完成时，执行该Runnable（不会捕获任务中的异常）
 * * {@link CompletableFuture#thenRun(Runnable)}
 * * {@link CompletableFuture#thenRunAsync(Runnable)}
 * * {@link CompletableFuture#thenRunAsync(Runnable, Executor)}
 * <p>
 * * thenCompose：当任务完成时，在新的CompletableFuture中对结果做一次转换，（不会捕获任务中的异常）
 * * {@link CompletableFuture#thenCompose(Function)}
 * * {@link CompletableFuture#thenComposeAsync(Function)}
 * * {@link CompletableFuture#thenComposeAsync(Function, Executor)}
 * <p>
 * * exceptionally：发生异常时，进行一次结果转换
 * * {@link CompletableFuture#exceptionally(Function)}
 * * {@link CompletableFuture#exceptionallyAsync(Function)}
 * * {@link CompletableFuture#exceptionallyAsync(Function, Executor)}
 * <p>
 * * exceptionally：发生异常时，在新的CompletableFuture中进行一次结果转换
 * * {@link CompletableFuture#exceptionallyCompose(Function)}
 * * {@link CompletableFuture#exceptionallyComposeAsync(Function)}
 * * {@link CompletableFuture#exceptionallyComposeAsync(Function, Executor)}
 * *****************************************************************************************************************************************
 * 3. 异步合并
 * * thenCombine：用于连接两个独立的CompletableFuture，当两个任务都完成时，将结果合并成一个新的有返回值的CompletableFuture
 * * {@link CompletableFuture#thenCombine(CompletionStage, BiFunction)}
 * * {@link CompletableFuture#thenCombineAsync(CompletionStage, BiFunction)}
 * * {@link CompletableFuture#thenCombineAsync(CompletionStage, BiFunction, Executor)}
 * <p>
 * * thenAcceptBoth：用于连接两个独立的CompletableFuture，当两个任务都完成时，将结果合并成一个新的无返回值的CompletableFuture
 * * {@link CompletableFuture#thenAcceptBoth(CompletionStage, BiConsumer)}
 * * {@link CompletableFuture#thenAcceptBothAsync(CompletionStage, BiConsumer)}
 * * {@link CompletableFuture#thenAcceptBothAsync(CompletionStage, BiConsumer, Executor)}
 * <p>
 * * runAfterBoth：用于连接两个独立的CompletableFuture,当两个任务完成时,执行一个新任务
 * * {@link CompletableFuture#runAfterBoth(CompletionStage, Runnable)}
 * * {@link CompletableFuture#runAfterBothAsync(CompletionStage, Runnable)}
 * * {@link CompletableFuture#runAfterBothAsync(CompletionStage, Runnable, Executor)}
 * <p>
 * * applyToEither：用于连接两个独立的CompletableFuture,最快返回输出的线程结果作为下一次任务的输入,并返回一个新的有返回值的CompletableFuture
 * * {@link CompletableFuture#applyToEither(CompletionStage, Function)}
 * * {@link CompletableFuture#applyToEitherAsync(CompletionStage, Function)}
 * * {@link CompletableFuture#applyToEitherAsync(CompletionStage, Function, Executor)}
 * <p>
 * * applyToEither：用于连接两个独立的CompletableFuture,最快返回输出的线程结果作为下一次任务的输入,并返回一个新的无返回值的CompletableFuture
 * * {@link CompletableFuture#acceptEither(CompletionStage, Consumer)}
 * * {@link CompletableFuture#acceptEitherAsync(CompletionStage, Consumer)}
 * * {@link CompletableFuture#acceptEitherAsync(CompletionStage, Consumer, Executor)}
 * <p>
 * * runAfterEither：用于连接两个独立的CompletableFuture,最快返回输出的线程结果作为下一次任务的输入,不返回
 * * {@link CompletableFuture#runAfterEither(CompletionStage, Runnable)}
 * * {@link CompletableFuture#runAfterEitherAsync(CompletionStage, Runnable)}
 * * {@link CompletableFuture#runAfterEitherAsync(CompletionStage, Runnable, Executor)}
 * <p>
 * * {@link CompletableFuture#allOf(CompletableFuture[])} 全部完成
 * * {@link CompletableFuture#anyOf(CompletableFuture[])} 任意一个完成
 * <p>
 *
 * @author 王霄
 * @date 2021/5/28
 */
public class CompletableFutureDemo {

    public static void main(String[] args) throws IOException {
        TimeInterval timer = DateUtil.timer();

        //阻塞一个任务集合

        //java11
        var t1 = CompletableFuture.runAsync(() -> task(2, "1"));
        var t2 = CompletableFuture.runAsync(() -> task(2, "2"));
        var t3 = CompletableFuture.runAsync(() -> task(3, "3"));
        var ts1 = List.of(t1, t2, t3);
        var r1 = CompletableFuture.allOf(ts1.toArray(CompletableFuture[]::new));
        r1.join();

        System.out.println("timer.intervalMs() = " + timer.intervalMs());

        System.out.println("-------------------------------------");

        //java8
        var t4 = CompletableFuture.runAsync(() -> task(1, "4"));
        var t5 = CompletableFuture.runAsync(() -> task(5, "5"));
        var t6 = CompletableFuture.runAsync(() -> task(2, "6"));
        var ts2 = List.of(t4, t5, t6);
        var r2 = CompletableFuture.allOf(ts2.toArray(new CompletableFuture[0]));
        r2.join();
        System.out.println("timer.intervalMs() = " + timer.intervalMs());
    }

    private static void task(int taskSecond, Object taskName) {
        try {
            TimeUnit.SECONDS.sleep(taskSecond);
            System.out.printf("任务%s完成%n", taskName);
        } catch (InterruptedException ignored) {
        }
    }

}
